Skip to content

Fix iOS Metro reload after initial bundle failure - #58352

Open
janicduplessis wants to merge 6 commits into
react:mainfrom
janicduplessis:@janic/ios-simulator-reload
Open

Fix iOS Metro reload after initial bundle failure#58352
janicduplessis wants to merge 6 commits into
react:mainfrom
janicduplessis:@janic/ios-simulator-reload

Conversation

@janicduplessis

@janicduplessis janicduplessis commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Summary:

In bridgeless iOS apps, RCTInstance currently resolves DevSettings only after the initial bundle has loaded successfully. RCTDevSettings.initialize owns the Metro reload message handler, so an app whose first bundle request fails remains alive but cannot receive the same Metro reload command that Android handles natively.

Resolve DevSettings from the existing bundle-error handler after its instance-validity check. This preserves the successful-load timing and HMR setup, establishes the Metro command connection on the initial bundle-error path, and avoids initializing a stale connection when an in-flight request completes after invalidation. The module is not retained across the asynchronous request.

The lifecycle tests assert that DevSettings remains uninitialized while the request is pending, initializes when the initial bundle request fails, and stays uninitialized when that request completes after invalidation.

Changelog:

[IOS] [FIXED] - Allow Metro reload after an initial bundle-load failure.

Test Plan:

  • Ran the focused RCTInstanceTests.testInitializesDevSettingsAfterBundleLoadFailure and RCTInstanceTests.testDoesNotInitializeDevSettingsAfterInvalidation XCTest cases on an iOS 26.5 simulator: 2 tests, 0 failures.
  • Reinstated the rejected callback-level lookup as a negative control; the invalidation test failed with one unexpected DevSettings initialization.
  • Built the RNTester unit-test target from source successfully.
  • On patched RNTester, launched with an unresolved import on the initial bundle, restored the source, and waited 10 seconds. The error remained and Metro received no bundle request. Sent {version: 2, method: "reload"} to Metro; RNTester requested a corrected bundle and recovered with native PID 95823 unchanged. A consecutive Metro reload also completed with PID 95823 unchanged.
  • Repeated the comparison on Android RNTester. Android already receives the Metro command on the initial-error path and recovered with native PID 14848 unchanged.
  • When RNTester launched while Metro was entirely unavailable, it used its embedded bundle and did not become a message-socket peer merely because Metro later started. That distinct no-peer case still requires a native reload or app/deep-link fallback.

Android expected-behavior comparison:

rntester-android-reload-full.mp4

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Sep 4, 2026
@facebook-github-tools facebook-github-tools Bot added Contributor A React Native contributor. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. labels Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Contributor A React Native contributor. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant